package model

import (
	"context"
	"database/sql"
	"fmt"
	"portal/internal/common"
	"portal/internal/errorx"
	"portal/internal/types"

	"github.com/Masterminds/squirrel"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

var _ SysUserModel = (*customSysUserModel)(nil)

type (
	// SysUserModel is an interface to be customized, add more methods here,
	// and implement the added methods in customSysUserModel.
	SysUserModel interface {
		sysUserModel
		withSession(session sqlx.Session) SysUserModel
		GetOneByUserName(ctx context.Context,session sqlx.Session, userName string)(*SysUser, error)
		GetOneWithDept(ctx context.Context, session sqlx.Session, userId int64) (*SysDeptUser, error)
		DelUserRoles(ctx context.Context, session sqlx.Session, userId int64, roleIds []*int64) error
		AddUserRoles(ctx context.Context, session sqlx.Session, userId int64, roleIds []*int64) error
		DelUserPosts(ctx context.Context, session sqlx.Session, userId int64, roleIds []*int64) error
		AddUserPosts(ctx context.Context, session sqlx.Session, userId int64, roleIds []*int64) error
		ListUserRoles(ctx context.Context,session sqlx.Session,userId int64)([]*SysUserRole,error)
		ListUserPosts(ctx context.Context,session sqlx.Session,userId int64)([]*SysUserPost,error)
		ExistByRidUid(ctx context.Context, session sqlx.Session, roleId int64, userId int64)error
		DelUser(ctx context.Context,session sqlx.Session,userId int64)(error)
		BulkInsert(context context.Context, session sqlx.Session, account []*SysUser) error
		InsertGetId(ctx context.Context, session sqlx.Session, data *SysUser) (int64, error)
		SelectOneByUname(ctx context.Context, session sqlx.Session, Uname string) (*SysUser, error)
		Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error
		Edit(ctx context.Context, session sqlx.Session, data *SysUser)error
		ListByCondition(ctx context.Context, session sqlx.Session, req *types.ListUserRequest,deptIds []*int64,isAdmin bool)([]*SysUser,error)
		CountByCondition(ctx context.Context, session sqlx.Session, req *types.ListUserRequest,deptIds []*int64,isAdmin bool)(*int64,error)
	}

	customSysUserModel struct {
		*defaultSysUserModel
	}
)

// NewSysUserModel returns a model for the database table.
func NewSysUserModel(conn sqlx.SqlConn) SysUserModel {
	return &customSysUserModel{
		defaultSysUserModel: newSysUserModel(conn),
	}
}

func (m *customSysUserModel) withSession(session sqlx.Session) SysUserModel {
	return NewSysUserModel(sqlx.NewSqlConnFromSession(session))
}

func (m *customSysUserModel) GetOneWithDept(ctx context.Context, session sqlx.Session, userId int64) (*SysDeptUser, error) {
	sb := squirrel.
		Select("user.*,dept.dept_name,dept.leader,dept.phone as leader_phone,dept.email as leader_email").
		From(m.table + " user").
		Where(squirrel.Eq{"user.user_id": userId}).
		Where(squirrel.Eq{"user.del_flag":common.EXIST_FLAG}).
		InnerJoin("sys_dept dept on dept.dept_id = user.dept_id").
		Limit(1)
	query, args, err := sb.ToSql()
	if err != nil {
		return nil, err
	}
	var user SysDeptUser
	if session != nil {
		err = session.QueryRowCtx(ctx, &user, query, args...)
	} else {
		err = m.conn.QueryRowCtx(ctx, &user, query, args...)
	}
	return &user, err
}

func (m *customSysUserModel) DelUserRoles(ctx context.Context, session sqlx.Session, userId int64, roleIds []*int64) error {
	db := squirrel.Delete("sys_user_role").
		Where(squirrel.Eq{"user_id": userId}).
		Where(squirrel.Eq{"role_id": roleIds})
	query, args, err := db.ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_, err = session.ExecCtx(ctx, query, args...)
	} else {
		_, err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}

func (m *customSysUserModel) AddUserRoles(ctx context.Context, session sqlx.Session, userId int64, roleIds []*int64) error {
	ib := squirrel.Insert("").Into("sys_user_role").
		Columns("user_id", "role_id")
	for _, val := range roleIds {
		ib = ib.Values(userId, val)
	}
	query, args, err := ib.ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_, err = session.ExecCtx(ctx, query, args...)
	} else {
		_, err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}

func (m *customSysUserModel) DelUserPosts(ctx context.Context, session sqlx.Session, userId int64, postIds []*int64) error {
	db := squirrel.Delete("sys_user_post").
		Where(squirrel.Eq{"user_id": userId}).
		Where(squirrel.Eq{"post_id": postIds})
	query, args, err := db.ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_, err = session.ExecCtx(ctx, query, args...)
	} else {
		_, err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}

func (m *customSysUserModel) AddUserPosts(ctx context.Context, session sqlx.Session, userId int64, postIds []*int64) error {
	ib := squirrel.Insert("").Into("sys_user_post").
		Columns("user_id", "post_id")
	for _, val := range postIds {
		ib = ib.Values(userId, val)
	}
	query, args, err := ib.ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_, err = session.ExecCtx(ctx, query, args...)
	} else {
		_, err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}

func (m *customSysUserModel)ListUserRoles(ctx context.Context,session sqlx.Session,userId int64)([]*SysUserRole,error){
	sb := squirrel.Select("*").
		From("sys_user_role").
		Where(squirrel.Eq{"user_id":userId})
	query, args, err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var urs []*SysUserRole
	if session != nil {
		err = session.QueryRowsPartialCtx(ctx, &urs, query, args...)
	} else {
		err = m.conn.QueryRowsPartialCtx(ctx, &urs, query, args...)
	}
	return urs, err
}

func (m *customSysUserModel)ListUserPosts(ctx context.Context,session sqlx.Session,userId int64)([]*SysUserPost,error){
	sb := squirrel.Select("*").
		From("sys_user_post").
		Where(squirrel.Eq{"user_id":userId})
	query, args, err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var ups []*SysUserPost
	if session != nil {
		err = session.QueryRowsPartialCtx(ctx, &ups, query, args...)
	} else {
		err = m.conn.QueryRowsPartialCtx(ctx, &ups, query, args...)
	}
	return ups, err
}

func (m *customSysUserModel)ExistByRidUid(ctx context.Context, session sqlx.Session, roleId int64, userId int64)error{
	sb := squirrel.Select("1").From("sys_user_role").
			Where(squirrel.Eq{"role_id":roleId}).
			Where(squirrel.Eq{"user_id":userId}).
			Limit(1)
	query,args,err := sb.ToSql()
	if err != nil {
		return err
	}
	var count int64
	if session != nil {
		err = session.QueryRowPartialCtx(ctx, &count, query, args...)
	} else {
		err = m.conn.QueryRowPartialCtx(ctx, &count,query, args...)
	}
	if err != nil || count <= 0 {
		return errorx.SqlExistError
	}
	return nil
}

func (m *customSysUserModel)GetOneByUserName(ctx context.Context,session sqlx.Session, userName string)(*SysUser, error){
	sb := squirrel.Select("1").From(m.table).
			Where(squirrel.Eq{"user_name":userName}).
			Where(squirrel.Eq{"del_flag":common.EXIST_FLAG}).
			Limit(1)
	query,args,err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var user SysUser
	if session != nil {
		err = session.QueryRowPartialCtx(ctx, &user, query, args...)
	} else {
		err = m.conn.QueryRowPartialCtx(ctx, &user, query, args...)
	}
	return &user,err
}

func (m *customSysUserModel)DelUser(ctx context.Context,session sqlx.Session,userId int64)(error){
	ub := squirrel.Update(m.table).
		Set("del_flag",common.DELETED_FLAG).
		Where(squirrel.Eq{"user_id":userId})
	query, args, err := ub.ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_, err = session.ExecCtx(ctx, query, args...)
	} else {
		_, err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}

func (m *customSysUserModel) BulkInsert(context context.Context, session sqlx.Session, accounts []*SysUser) error {
	// conn := sqlx.NewSqlConnFromSession(session)
	var conn sqlx.SqlConn
	if session != nil {
		conn = sqlx.NewSqlConnFromSession(session)
	}else{
		conn = m.conn
	}
	query := fmt.Sprintf("insert into sys_user (dept_id,nick_name,user_name,user_type,email,phonenumber,sex,avatar,password,status,del_flag,login_ip,login_date,pwd_update_date,create_by,create_time,update_by,update_time) values (? ,? ,?, ?, ? ,? ,?, ?,? ,? ,?, ?, ?, ?, ?, ?, ?, ?)")
	bulk, err := sqlx.NewBulkInserter(conn, query)
	if err != nil {
		return errorx.NewBizError(500, "批量插入问题选项失败")
	}
	defer bulk.Flush()
	for _, val := range accounts {
		fmt.Printf("%+v\n",val)
		err = bulk.Insert((*val).DeptId.Int64, (*val).NickName, (*val).UserName, (*val).UserType, (*val).Email, (*val).Phonenumber, (*val).Sex, (*val).Avatar, (*val).Password, (*val).Status, (*val).DelFlag, (*val).LoginIp,(*val).LoginDate,(*val).PwdUpdateDate,(*val).CreateBy,(*val).CreateTime,(*val).UpdateBy,(*val).UpdateTime)
		if err != nil {
			return err
		}
	}
	return nil
}

func (m *customSysUserModel) SelectOneByUname(ctx context.Context, session sqlx.Session, Uname string) (*SysUser, error) {
	query, args, err := squirrel.Select("*").From(m.table).Where("user_name = ?", Uname).Limit(1).ToSql()
	if err != nil {
		return nil, err
	}
	var account SysUser
	if session != nil {
		err = session.QueryRowCtx(ctx, &account, query, args...)
	} else {
		err = m.conn.QueryRowCtx(ctx, &account, query, args...)
	}
	return &account, err

}

func (m *customSysUserModel) InsertGetId(ctx context.Context, session sqlx.Session, data *SysUser) (int64, error) {
	query, args, err := squirrel.Insert(m.table).Columns(sysUserInsertRows).
		Values(data.DeptId.Int64, data.NickName, data.UserName, data.UserType, data.Email, data.Phonenumber, data.Sex, data.Avatar, data.Password, data.Status, data.DelFlag, data.LoginIp,data.LoginDate,data.PwdUpdateDate,data.CreateBy,(data.CreateTime),(data.UpdateBy),data.UpdateTime,data.Remark).
		ToSql()
	if err != nil {
		return 0, err
	}
	var sqlRes sql.Result
	if session != nil {
		sqlRes,err = session.ExecCtx(ctx, query, args...)
	} else {
		sqlRes,err = m.conn.ExecCtx(ctx, query, args...)
	}
	if err != nil {
		return 0, err
	}
	id,err := sqlRes.LastInsertId()
	return id, err
}

// func (m *customAwAccountsModel)FindListByQid(ctx context.Context,session sqlx.Session,qId int64)([]*AwAccounts,error){
// 	builder := m.SelectBuilder().Where(squirrel.Eq{"question_id":qId})
// 	query,values,err := builder.ToSql()
// 	if err != nil {
// 		return nil,err
// 	}
// 	var options []*AwAccounts
// 	err = m.conn.QueryRowsPartialCtx(ctx,&options,query,values...)
// 	if err != nil {
// 		return nil,err
// 	}
// 	return options,nil
// }

func (m *customSysUserModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error {
	return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
		return fn(ctx, session)
	})
}

func (m *customSysUserModel)CountByCondition(ctx context.Context, session sqlx.Session, req *types.ListUserRequest,deptIds []*int64,isAdmin bool)(*int64,error){
	sb := squirrel.Select("count(*)").From(m.table)
	if len(req.UserName) > 0 {
		sb = sb.Where(squirrel.Like{"user_name":`%`+req.UserName+`%`})
	}
	if len(req.Phonenumber) > 0 {
		sb = sb.Where(squirrel.Like{"phonenumber":`%`+req.Phonenumber+`%`})
	}
	if len(req.Status) > 0 {
		sb =sb.Where(squirrel.Eq{"status":req.Status})
	}
	if req.BeginTime > 0 {
		sb = sb.Where(squirrel.Gt{"update_time":req.BeginTime})
	}
	if req.EndTime > 0 {
		sb = sb.Where(squirrel.Lt{"update_time":req.EndTime})
	}
	if len(deptIds) > 0 {
		sb = sb.Where(squirrel.Eq{"dept_id":deptIds})
	}else {
		if !isAdmin {
			return nil,ErrNotFound
		}
	}
	query, args, err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var count int64
	if session != nil {
		err = session.QueryRowCtx(ctx, &count, query, args...)
	} else {
		err = m.conn.QueryRowCtx(ctx, &count, query, args...)
	}
	return &count, err
}

func (m *customSysUserModel)ListByCondition(ctx context.Context, session sqlx.Session, req *types.ListUserRequest,deptIds []*int64,isAdmin bool)([]*SysUser,error){
	sb := squirrel.Select("*").From(m.table)
	if len(req.UserName) > 0 {
		sb = sb.Where(squirrel.Eq{"user_name":req.UserName})
	}
	if len(req.Phonenumber) > 0 {
		sb = sb.Where(squirrel.Eq{"phonenumber":req.Phonenumber})
	}
	if len(req.Status) > 0 {
		sb =sb.Where(squirrel.Eq{"status":req.Status})
	}
	if req.BeginTime > 0 {
		sb = sb.Where(squirrel.Gt{"update_time":req.BeginTime})
	}
	if req.EndTime > 0 {
		sb = sb.Where(squirrel.Lt{"update_time":req.EndTime})
	}
	if len(deptIds) > 0 {
		sb = sb.Where(squirrel.Eq{"dept_id":deptIds})
	}else {
		if !isAdmin {
			return nil,ErrNotFound
		}
	}
	sb = sb.Offset(uint64((req.PageNum - 1) * (req.PageSize))).Limit(uint64(req.PageSize))
	query, args, err := sb.ToSql()
	if err != nil {
		return nil,err
	}
	var ups []*SysUser
	if session != nil {
		err = session.QueryRowsPartialCtx(ctx, &ups, query, args...)
	} else {
		err = m.conn.QueryRowsPartialCtx(ctx, &ups, query, args...)
	}
	return ups, err
}

func (m *customSysUserModel)Edit(ctx context.Context, session sqlx.Session, data *SysUser)error{	
	
	query,args,err := squirrel.Update(m.table).
		SetMap(
			squirrel.Eq{
				"dept_id":data.DeptId,
				"nick_name":data.NickName,
				"user_name":data.UserName,
				"user_type":data.UserType,
				"email":data.Email,
				"phonenumber":data.Phonenumber,
				"sex":data.Sex,
				"avatar":data.Avatar,
				"password":data.Password,
				"del_flag":data.DelFlag,
				"login_ip":data.LoginIp,
				"login_date":data.LoginDate,
				"pwd_update_date":data.PwdUpdateDate,
				"status":data.Status,
				"update_time":data.UpdateTime,
				"update_by":data.UpdateBy,
			}).
		Where(squirrel.Eq{"user_id":data.UserId}).
		ToSql()
	if err != nil {
		return err
	}
	if session != nil {
		_,err = session.ExecCtx(ctx, query, args...)
	} else {
		_,err = m.conn.ExecCtx(ctx, query, args...)
	}
	return err
}